package kgame5.k3d.core.parser {
import kgame5.k3d.core.math.NumberUV;
import kgame5.k3d.core.math.Vertex3D;
import kgame5.k3d.core.obj3d.info.geometry.Face3D;
import kgame5.k3d.core.obj3d.info.geometry.GeometryInfo;
import kgame5.k3d.core.obj3d.node3d.animator.Animator3D;
import kgame5.k3d.core.obj3d.node3d.animator.KeyFrame3D;

import flash.utils.ByteArray;
import flash.utils.Endian;

/**
 * @author kangkai
 * 解析MD2格式的文件
 * 注意，这个的170行里我强制校正了位置
 * 
 * 注意,这个加载md2的时候是等有个各个face之后，才设置gi的，这样保证了无论如何都是有贴图的,并且每个面也都有贴图
 */
public class MD2Parser {
		private var loadScale:Number=1;
		private var _fps:int=20;
		/**
		 * MD2 Header data
		 * These are all the variables found in the md2_header_t
		 * C style struct that starts every MD2 file.
		 */
		private var ident:int, version:int;
		private var skinwidth:int, skinheight:int;
		private var framesize:int;
		private var num_skins:int, num_vertices:int, num_st:int;
		private var num_tris:int, num_glcmds:int, num_frames:int;
		private var offset_skins:int, offset_st:int, offset_tris:int;
		private var offset_frames:int, offset_glcmds:int, offset_end:int;
		
		public var animator:Animator3D;
		
		public function MD2Parser(fps:int){
			_fps=fps;
		}
		
	/**
		 * <p>Parses the MD2 file. This is actually pretty straight forward.
		 * Only complicated parts (bit convoluded) are the frame loading
		 * and "metaface" loading. Hey, it works, use it =)</p>
		 * 
		 * @param	data	A ByteArray
		 */
		public function parse(data:ByteArray):Animator3D{
			
		
			var gi:GeometryInfo=new GeometryInfo();
			animator=new Animator3D();
			
			
			var i:int;
			
			data.endian = Endian.LITTLE_ENDIAN;
			
			// Read the header and make sure it is valid MD2 file
			readMd2Header(data);
			if (ident != 844121161 || version != 8){
				throw new Error("error loading MD2 file (" + "!!" + "): Not a valid MD2 file/bad version");
			}
			
			//---Vertice setup
			// be sure to allocate memory for the vertices to the object
			for (i = 0; i < num_vertices; i++){
				gi.aVertex.push(new Vertex3D(0,0,0));
			}
			
			//---UV coordinates
			data.position = offset_st;
			for (i = 0; i < num_st; i++){
				var uv:NumberUV = new NumberUV(data.readShort() / skinwidth, data.readShort() / skinheight);
				//uv.v = 1 - uv.v;
				gi.aNumberUV.push(uv);
			}

			//---Frame animation data
			data.position = offset_frames;
			var frameList:Array=readFrames(data,gi);
			animator.setupKeyframeList(frameList);
			
			//---Faces
			// make sure to push the faces with allocated vertices to the object!
			data.position = offset_tris;
			for (i = 0; i < num_tris; i++){
				var a:int= data.readUnsignedShort();
				var  b:int= data.readUnsignedShort();
				var c:int= data.readUnsignedShort();
				var ta:int= data.readUnsignedShort(); 
				var tb:int= data.readUnsignedShort();
				var  tc:int= data.readUnsignedShort();

				gi.aFace.push(new Face3D(gi,c,b,a,tc,tb,ta));
			}
			
			//放在这里是为了防止出错用的
			animator.setGeometryInfo(gi);
			
			return animator;
		}
		
		/**
		 * Reads in all the frames
		 */
		protected function readFrames(data:ByteArray,gi:GeometryInfo):Array{
			var sx:Number, sy:Number, sz:Number;
			var tx:Number, ty:Number, tz:Number;
			
			var i:int, j:int,char:int;
			var duration:Number = 1 / _fps;
			
			var keyframeList:Array=new Array();
			
			for (i = 0; i < num_frames; i++){				
				sx = data.readFloat();
				sy = data.readFloat();
				sz = data.readFloat();
				
				tx = data.readFloat();
				ty = data.readFloat();
				tz = data.readFloat();
				
				//这个读取名字不能少，少了就读乱了
				var frameName:String = "";
				for (j = 0; j < 16; j++){
					if ((char = data.readUnsignedByte()) != 0){
						frameName += String.fromCharCode(char);
					}
				}
				
				var vertices:Vector.<Vertex3D>;
				 vertices= new Vector.<Vertex3D>();

				// Note, the extra data.position++ in the for loop is there 
				// to skip over a byte that holds the "vertex normal index"
				for (j = 0; j < num_vertices; j++, data.position++){
					var v:Vertex3D = new Vertex3D(0,0,0);
					
					//原始的
//					v.x=sx * data.readUnsignedByte() + tx * loadScale;
//					v.y=sy * data.readUnsignedByte() + ty * loadScale;
//					v.z=sz * data.readUnsignedByte() + tz * loadScale;
//					v.x = -v.x;
					
					//新校正过的
					v.x=sx * data.readUnsignedByte() + tx * loadScale;
					v.z=sy * data.readUnsignedByte() + ty * loadScale;
					v.y=sz * data.readUnsignedByte() + tz * loadScale;
					v.z = -v.z;
					v.x = -v.x;
					
						
					if( i == 0 ){//把第一帧的数据都放到gi.aVertex里
						
						gi.aVertex[j].x = v.x;
						gi.aVertex[j].y = v.y;
						gi.aVertex[j].z = v.z;
					}
					
					vertices.push(v);
				}
				
				//注意这里keyframe的time是暂时的，组装成动作的时候要填入正确的
				keyframeList.push(new KeyFrame3D("keyframe_"+i, i * duration, vertices));

			}
			
			return keyframeList;
		}
		
		/**
		 * Reads in all that MD2 Header data that is declared as private variables.
		 * I know its a lot, and it looks ugly, but only way to do it in Flash
		 */
		protected function readMd2Header(data:ByteArray):void
		{
			ident = data.readInt();
			version = data.readInt();
			skinwidth = data.readInt();
			skinheight = data.readInt();
			framesize = data.readInt();
			num_skins = data.readInt();
			num_vertices = data.readInt();
			num_st = data.readInt();
			num_tris = data.readInt();
			num_glcmds = data.readInt();
			num_frames = data.readInt();
			offset_skins = data.readInt();
			offset_st = data.readInt();
			offset_tris = data.readInt();
			offset_frames = data.readInt();
			offset_glcmds = data.readInt();
			offset_end = data.readInt();
		}
}
}
////////////////////////////////////////
/*
		protected function readFrames(data:ByteArray,actionList:Dictionary,gi:GeometryInfo,animator:Animator3D):void{
			var sx:Number, sy:Number, sz:Number;
			var tx:Number, ty:Number, tz:Number;
			
			var i:int, j:int, char:int;
			var duration:Number = 1 / _fps;
			
			//存储全部的动作
			var action_all:AbstractChannel3D = new MorphChannel3D(animator, "all");
			
			var t:uint = 0;
			
			var curName:String = "all";
			var action:AbstractChannel3D;
			var framePos:int = 0;//frame在一个动作里的序号,用这个来计算时间
			
			for (i = 0; i < num_frames; i++){				
				sx = data.readFloat();
				sy = data.readFloat();
				sz = data.readFloat();
				
				tx = data.readFloat();
				ty = data.readFloat();
				tz = data.readFloat();
				
				var frameName:String = "";
				
				for (j = 0; j < 16; j++){
					if ((char = data.readUnsignedByte()) != 0){
						frameName += String.fromCharCode(char);
					}
				}
				
				//trace(i,frameName);
				
				var shortName:String = frameName.replace(/\d+/, "");
				
				if(curName != shortName){
					if(action){
						actionList[action.name] = action;
					}
					
					action = new MorphChannel3D(animator, shortName);
					curName = shortName;
					framePos = 0;
				}
				
				var vertices:Vector.<Vertex3D>;
				 vertices= new Vector.<Vertex3D>();

				// Note, the extra data.position++ in the for loop is there 
				// to skip over a byte that holds the "vertex normal index"
				for (j = 0; j < num_vertices; j++, data.position++){
					var v:Vertex3D = new Vertex3D(0,0,0);
					
					//原始的
//					v.x=sx * data.readUnsignedByte() + tx * loadScale;
//					v.y=sy * data.readUnsignedByte() + ty * loadScale;
//					v.z=sz * data.readUnsignedByte() + tz * loadScale;
//					v.x = -v.x;
					
					//新校正过的
					v.x=sx * data.readUnsignedByte() + tx * loadScale;
					v.z=sy * data.readUnsignedByte() + ty * loadScale;
					v.y=sz * data.readUnsignedByte() + tz * loadScale;
					v.z = -v.z;
					v.x = -v.x;
					
						
					if( i == 0 ){//把第一帧的数据都放到gi.aVertex里
						
//						animator.gi.aVertex[j].x = v.x;
//						animator.gi.aVertex[j].y = v.y;
//						animator.gi.aVertex[j].z = v.z;
						gi.aVertex[j].x = v.x;
						gi.aVertex[j].y = v.y;
						gi.aVertex[j].z = v.z;
					}
					
					vertices.push(v);
				}
				
				action.addKeyFrame(new KeyFrame3D(frameName, framePos * duration, vertices));
				
				action_all.addKeyFrame(new KeyFrame3D(frameName, i * duration, vertices));
				
				//trace(clipPos * duration,clipPos,duration,i);
				
				framePos++;
			}
			
			//这个是因为for循环的最后一个action还没 加上呢，所以用这个
			if(action){
				actionList[action.name] = action;
			}
			
			//全部的动作
			actionList[action_all.name] = action_all;
		}
//*/